Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/vlselect/logsql/logsql.go
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,8 @@ func ProcessTenantIDsRequest(ctx context.Context, w http.ResponseWriter, r *http
httpserver.Errorf(w, r, "cannot obtain tenantIDs: %s", err)
return
}
// Return tenants in a deterministic (sorted) order for stable API responses.
logstorage.SortTenantIDs(tenants)
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated

data, err := json.Marshal(tenants)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions app/vlstorage/netselect/netselect.go
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,7 @@ func (s *Storage) getTenantIDs(ctx context.Context, start, end int64) ([]logstor
tenantIDs = append(tenantIDs, tenantID)
}

logstorage.SortTenantIDs(tenantIDs)
return tenantIDs, nil
}

Expand Down
1 change: 1 addition & 0 deletions docs/victorialogs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ according to the following docs:
* BUGFIX: [cluster version](https://docs.victoriametrics.com/victorialogs/cluster/): avoid `cannot connect to storage node at ...: EOF` errors after `vlselect` or `vlinsert` was idle for more than 60 seconds. See [#1440](https://github.com/VictoriaMetrics/VictoriaLogs/issues/1440).
* BUGFIX: [vlselect](https://docs.victoriametrics.com/victorialogs/cluster/): return `502 Bad Gateway` HTTP response code for incoming queries when one of the `vlstorage` nodes runs a VictoriaLogs version with an incompatible internal API instead of `400 Bad Request`. This is consistent with the `502 Bad Gateway` response returned when a `vlstorage` node is unavailable, and it allows building a proper failover scheme in high-availability setups. See [these docs](https://docs.victoriametrics.com/victorialogs/cluster/#high-availability).
* BUGFIX: [multi-level cluster setup](https://docs.victoriametrics.com/victorialogs/cluster/#multi-level-cluster-setup): properly return `502 Bad Gateway` HTTP response code when a `vlselect` node queries other `vlselect` nodes and the underlying `vlstorage` is unavailable, as described at [high availability](https://docs.victoriametrics.com/victorialogs/cluster/#high-availability) docs. This allows configuring proper failover schemes to a healthy cluster.
* BUGFIX: [`/select/tenant_ids`](https://docs.victoriametrics.com/victorialogs/querying/#querying-tenants): return tenant ids in a deterministic (sorted) order. Previously the order was random across requests. See [#1575](https://github.com/VictoriaMetrics/VictoriaLogs/pull/1575).

## [v1.51.0](https://github.com/VictoriaMetrics/VictoriaLogs/releases/tag/v1.51.0)

Expand Down
6 changes: 6 additions & 0 deletions lib/logstorage/storage_search.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ func (s *Storage) runQuery(qctx *QueryContext, writeBlock writeBlockResultFunc)
}

func (s *Storage) getSearchOptions(tenantIDs []TenantID, q *Query, hiddenFieldsFilters []string) *storageSearchOptions {
// tenantIDs must be sorted, since block search performs binary search over them.
SortTenantIDs(tenantIDs)

streamIDs := q.getStreamIDs()
sort.Slice(streamIDs, func(i, j int) bool {
return streamIDs[i].less(&streamIDs[j])
Expand Down Expand Up @@ -752,6 +755,9 @@ func (s *Storage) getTenantIDs(ctx context.Context, start, end int64) ([]TenantI
for k := range uniqTenantIDs {
tenants = append(tenants, k)
}
// Sort tenants, since they are collected from a map with random iteration order.
// This provides stable output and a sorted list for callers that rely on it.
SortTenantIDs(tenants)

return tenants, nil
}
Expand Down
8 changes: 2 additions & 6 deletions lib/logstorage/storage_search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -675,12 +675,8 @@ func TestStorageRunQuery(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
sort.Slice(tenantIDs, func(i, j int) bool {
return tenantIDs[i].less(&tenantIDs[j])
})
sort.Slice(allTenantIDs, func(i, j int) bool {
return allTenantIDs[i].less(&allTenantIDs[j])
})
SortTenantIDs(tenantIDs)
SortTenantIDs(allTenantIDs)
if !reflect.DeepEqual(tenantIDs, allTenantIDs) {
t.Fatalf("unexpected GetTenantIDs result; got: %v, want: %v", tenantIDs, allTenantIDs)
}
Expand Down
8 changes: 8 additions & 0 deletions lib/logstorage/tenant_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"sort"
"strconv"
"strings"

Expand Down Expand Up @@ -46,6 +47,13 @@ func (tid *TenantID) less(a *TenantID) bool {
return tid.ProjectID < a.ProjectID
}

// SortTenantIDs sorts tenantIDs in place in ascending order.
func SortTenantIDs(tenantIDs []TenantID) {
sort.Slice(tenantIDs, func(i, j int) bool {
return tenantIDs[i].less(&tenantIDs[j])
})
}

func (tid *TenantID) marshalString(dst []byte) []byte {
n := uint64(tid.AccountID)<<32 | uint64(tid.ProjectID)
dst = marshalUint64Hex(dst, n)
Expand Down