release: v2.0.4 (#217)

* perf(routes): batch cross-IATA and hash route search (#216)

One search fired a /routes/cross request per IATA pair (138k on 2026-10-08). Route search now takes an optional iatas list and runs a fixed number of index-backed queries. /info advertises built-in minimum client versions.

* chore: bump version to 2.0.4
This commit is contained in:
MrAlders0n
2026-10-09 22:17:23 -04:00
committed by GitHub
parent 768889243c
commit 9bbf8efee5
37 changed files with 1625 additions and 591 deletions
+89 -29
View File
@@ -432,21 +432,6 @@ func (mr *MockQuerierMockRecorder) GetChannelByID(ctx, id any) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChannelByID", reflect.TypeOf((*MockQuerier)(nil).GetChannelByID), ctx, id)
}
// GetCrossIATANeighbors mocks base method.
func (m *MockQuerier) GetCrossIATANeighbors(ctx context.Context, arg db.GetCrossIATANeighborsParams) ([]db.GetCrossIATANeighborsRow, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetCrossIATANeighbors", ctx, arg)
ret0, _ := ret[0].([]db.GetCrossIATANeighborsRow)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetCrossIATANeighbors indicates an expected call of GetCrossIATANeighbors.
func (mr *MockQuerierMockRecorder) GetCrossIATANeighbors(ctx, arg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCrossIATANeighbors", reflect.TypeOf((*MockQuerier)(nil).GetCrossIATANeighbors), ctx, arg)
}
// GetEarliestCompleteRollupHour mocks base method.
func (m *MockQuerier) GetEarliestCompleteRollupHour(ctx context.Context) (pgtype.Timestamptz, error) {
m.ctrl.T.Helper()
@@ -507,19 +492,19 @@ func (mr *MockQuerierMockRecorder) GetIATABorder(ctx, iata any) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetIATABorder", reflect.TypeOf((*MockQuerier)(nil).GetIATABorder), ctx, iata)
}
// GetKnownRoutesByNode mocks base method.
func (m *MockQuerier) GetKnownRoutesByNode(ctx context.Context, arg db.GetKnownRoutesByNodeParams) ([]db.GetKnownRoutesByNodeRow, error) {
// GetKnownRoutesByNodes mocks base method.
func (m *MockQuerier) GetKnownRoutesByNodes(ctx context.Context, arg db.GetKnownRoutesByNodesParams) ([]db.GetKnownRoutesByNodesRow, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetKnownRoutesByNode", ctx, arg)
ret0, _ := ret[0].([]db.GetKnownRoutesByNodeRow)
ret := m.ctrl.Call(m, "GetKnownRoutesByNodes", ctx, arg)
ret0, _ := ret[0].([]db.GetKnownRoutesByNodesRow)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetKnownRoutesByNode indicates an expected call of GetKnownRoutesByNode.
func (mr *MockQuerierMockRecorder) GetKnownRoutesByNode(ctx, arg any) *gomock.Call {
// GetKnownRoutesByNodes indicates an expected call of GetKnownRoutesByNodes.
func (mr *MockQuerierMockRecorder) GetKnownRoutesByNodes(ctx, arg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetKnownRoutesByNode", reflect.TypeOf((*MockQuerier)(nil).GetKnownRoutesByNode), ctx, arg)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetKnownRoutesByNodes", reflect.TypeOf((*MockQuerier)(nil).GetKnownRoutesByNodes), ctx, arg)
}
// GetLatestCompleteRollupHour mocks base method.
@@ -537,6 +522,21 @@ func (mr *MockQuerierMockRecorder) GetLatestCompleteRollupHour(ctx any) *gomock.
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestCompleteRollupHour", reflect.TypeOf((*MockQuerier)(nil).GetLatestCompleteRollupHour), ctx)
}
// GetNeighborLinks mocks base method.
func (m *MockQuerier) GetNeighborLinks(ctx context.Context, arg db.GetNeighborLinksParams) ([]db.GetNeighborLinksRow, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetNeighborLinks", ctx, arg)
ret0, _ := ret[0].([]db.GetNeighborLinksRow)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetNeighborLinks indicates an expected call of GetNeighborLinks.
func (mr *MockQuerierMockRecorder) GetNeighborLinks(ctx, arg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNeighborLinks", reflect.TypeOf((*MockQuerier)(nil).GetNeighborLinks), ctx, arg)
}
// GetNodeByID mocks base method.
func (m *MockQuerier) GetNodeByID(ctx context.Context, id uuid.UUID) (db.GetNodeByIDRow, error) {
m.ctrl.T.Helper()
@@ -1911,6 +1911,66 @@ func (mr *MockQuerierMockRecorder) ResolvePathHashesP4(ctx, arg any) *gomock.Cal
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolvePathHashesP4", reflect.TypeOf((*MockQuerier)(nil).ResolvePathHashesP4), ctx, arg)
}
// ResolveRelayHashPairsP1 mocks base method.
func (m *MockQuerier) ResolveRelayHashPairsP1(ctx context.Context, arg db.ResolveRelayHashPairsP1Params) ([]db.ResolveRelayHashPairsP1Row, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ResolveRelayHashPairsP1", ctx, arg)
ret0, _ := ret[0].([]db.ResolveRelayHashPairsP1Row)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ResolveRelayHashPairsP1 indicates an expected call of ResolveRelayHashPairsP1.
func (mr *MockQuerierMockRecorder) ResolveRelayHashPairsP1(ctx, arg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveRelayHashPairsP1", reflect.TypeOf((*MockQuerier)(nil).ResolveRelayHashPairsP1), ctx, arg)
}
// ResolveRelayHashPairsP2 mocks base method.
func (m *MockQuerier) ResolveRelayHashPairsP2(ctx context.Context, arg db.ResolveRelayHashPairsP2Params) ([]db.ResolveRelayHashPairsP2Row, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ResolveRelayHashPairsP2", ctx, arg)
ret0, _ := ret[0].([]db.ResolveRelayHashPairsP2Row)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ResolveRelayHashPairsP2 indicates an expected call of ResolveRelayHashPairsP2.
func (mr *MockQuerierMockRecorder) ResolveRelayHashPairsP2(ctx, arg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveRelayHashPairsP2", reflect.TypeOf((*MockQuerier)(nil).ResolveRelayHashPairsP2), ctx, arg)
}
// ResolveRelayHashPairsP3 mocks base method.
func (m *MockQuerier) ResolveRelayHashPairsP3(ctx context.Context, arg db.ResolveRelayHashPairsP3Params) ([]db.ResolveRelayHashPairsP3Row, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ResolveRelayHashPairsP3", ctx, arg)
ret0, _ := ret[0].([]db.ResolveRelayHashPairsP3Row)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ResolveRelayHashPairsP3 indicates an expected call of ResolveRelayHashPairsP3.
func (mr *MockQuerierMockRecorder) ResolveRelayHashPairsP3(ctx, arg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveRelayHashPairsP3", reflect.TypeOf((*MockQuerier)(nil).ResolveRelayHashPairsP3), ctx, arg)
}
// ResolveRelayHashPairsP4 mocks base method.
func (m *MockQuerier) ResolveRelayHashPairsP4(ctx context.Context, arg db.ResolveRelayHashPairsP4Params) ([]db.ResolveRelayHashPairsP4Row, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ResolveRelayHashPairsP4", ctx, arg)
ret0, _ := ret[0].([]db.ResolveRelayHashPairsP4Row)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ResolveRelayHashPairsP4 indicates an expected call of ResolveRelayHashPairsP4.
func (mr *MockQuerierMockRecorder) ResolveRelayHashPairsP4(ctx, arg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveRelayHashPairsP4", reflect.TypeOf((*MockQuerier)(nil).ResolveRelayHashPairsP4), ctx, arg)
}
// RollAdvertHearings mocks base method.
func (m *MockQuerier) RollAdvertHearings(ctx context.Context, hour pgtype.Timestamptz) error {
m.ctrl.T.Helper()
@@ -2178,19 +2238,19 @@ func (mr *MockQuerierMockRecorder) SaveZoneList(ctx, arg any) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveZoneList", reflect.TypeOf((*MockQuerier)(nil).SaveZoneList), ctx, arg)
}
// SearchKnownRoutes mocks base method.
func (m *MockQuerier) SearchKnownRoutes(ctx context.Context, arg db.SearchKnownRoutesParams) ([]db.SearchKnownRoutesRow, error) {
// SearchKnownRoutesByNodes mocks base method.
func (m *MockQuerier) SearchKnownRoutesByNodes(ctx context.Context, arg db.SearchKnownRoutesByNodesParams) ([]db.SearchKnownRoutesByNodesRow, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SearchKnownRoutes", ctx, arg)
ret0, _ := ret[0].([]db.SearchKnownRoutesRow)
ret := m.ctrl.Call(m, "SearchKnownRoutesByNodes", ctx, arg)
ret0, _ := ret[0].([]db.SearchKnownRoutesByNodesRow)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// SearchKnownRoutes indicates an expected call of SearchKnownRoutes.
func (mr *MockQuerierMockRecorder) SearchKnownRoutes(ctx, arg any) *gomock.Call {
// SearchKnownRoutesByNodes indicates an expected call of SearchKnownRoutesByNodes.
func (mr *MockQuerierMockRecorder) SearchKnownRoutesByNodes(ctx, arg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchKnownRoutes", reflect.TypeOf((*MockQuerier)(nil).SearchKnownRoutes), ctx, arg)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchKnownRoutesByNodes", reflect.TypeOf((*MockQuerier)(nil).SearchKnownRoutesByNodes), ctx, arg)
}
// SetNodeDefaultScope mocks base method.
+18 -6
View File
@@ -64,8 +64,6 @@ type Querier interface {
// Both counters only grow, so their sum changes whenever rolled content or coverage does.
GetAnalyticsRevision(ctx context.Context) (int64, error)
GetChannelByID(ctx context.Context, id int32) (Channel, error)
// Returns neighbors of a node that are in a different IATA.
GetCrossIATANeighbors(ctx context.Context, arg GetCrossIATANeighborsParams) ([]GetCrossIATANeighborsRow, error)
GetEarliestCompleteRollupHour(ctx context.Context) (pgtype.Timestamptz, error)
// ============================================================
// STATS
@@ -76,8 +74,13 @@ type Querier interface {
// when neither exists; a missing row (unknown IATA) is sql.ErrNoRows, same
// not-found distinction GetIATA already makes.
GetIATABorder(ctx context.Context, iata string) (json.RawMessage, error)
GetKnownRoutesByNode(ctx context.Context, arg GetKnownRoutesByNodeParams) ([]GetKnownRoutesByNodeRow, error)
// Routes containing @nodes[i] in IATA @iatas[i] (aligned, one node per IATA). The &&
// drives the node_ids GIN index; the indexed check keeps LIMIT counting real matches.
GetKnownRoutesByNodes(ctx context.Context, arg GetKnownRoutesByNodesParams) ([]GetKnownRoutesByNodesRow, error)
GetLatestCompleteRollupHour(ctx context.Context) (pgtype.Timestamptz, error)
// Neighbor rows between @a_nodes and @b_nodes in either orientation: ingest writes
// adverts as (sender, forwarder) but traces as (receiver, sender). Callers normalise.
GetNeighborLinks(ctx context.Context, arg GetNeighborLinksParams) ([]GetNeighborLinksRow, error)
GetNodeByID(ctx context.Context, id uuid.UUID) (GetNodeByIDRow, error)
GetNodeByPubkey(ctx context.Context, publicKey []byte) (uuid.UUID, error)
// Returns the neighbors of a node with details, ordered by most recently seen.
@@ -317,6 +320,14 @@ type Querier interface {
ResolvePathHashesP2(ctx context.Context, arg ResolvePathHashesP2Params) ([]ResolvePathHashesP2Row, error)
ResolvePathHashesP3(ctx context.Context, arg ResolvePathHashesP3Params) ([]ResolvePathHashesP3Row, error)
ResolvePathHashesP4(ctx context.Context, arg ResolvePathHashesP4Params) ([]ResolvePathHashesP4Row, error)
// Batch form of ResolvePathHashesP1 across IATAs; callers check uniqueness per IATA.
ResolveRelayHashPairsP1(ctx context.Context, arg ResolveRelayHashPairsP1Params) ([]ResolveRelayHashPairsP1Row, error)
// Batch form of ResolvePathHashesP2 across IATAs; callers check uniqueness per IATA.
ResolveRelayHashPairsP2(ctx context.Context, arg ResolveRelayHashPairsP2Params) ([]ResolveRelayHashPairsP2Row, error)
// Batch form of ResolvePathHashesP3 across IATAs; callers check uniqueness per IATA.
ResolveRelayHashPairsP3(ctx context.Context, arg ResolveRelayHashPairsP3Params) ([]ResolveRelayHashPairsP3Row, error)
// Batch form of ResolvePathHashesP4 across IATAs; callers check uniqueness per IATA.
ResolveRelayHashPairsP4(ctx context.Context, arg ResolveRelayHashPairsP4Params) ([]ResolveRelayHashPairsP4Row, error)
RollAdvertHearings(ctx context.Context, hour pgtype.Timestamptz) error
// Each distinct ADVERT packet counts once, under the exact set of IATAs that heard it this hour.
RollAdvertSets(ctx context.Context, hour pgtype.Timestamptz) error
@@ -347,9 +358,10 @@ type Querier interface {
SaveZoneBoundary(ctx context.Context, arg SaveZoneBoundaryParams) error
// NULL payload/etag/fetched_at retain the last good list after an error or 304.
SaveZoneList(ctx context.Context, arg SaveZoneListParams) error
// Returns known routes containing a subsequence from source to destination hash prefix.
// Verifies source appears before destination in the route.
SearchKnownRoutes(ctx context.Context, arg SearchKnownRoutesParams) ([]SearchKnownRoutesRow, error)
// Routes holding a source and a destination candidate; callers check order and IATA.
// A route's hops resolve in its own IATA, so candidates from other IATAs can't match.
// Both && predicates use the node_ids GIN index.
SearchKnownRoutesByNodes(ctx context.Context, arg SearchKnownRoutesByNodesParams) ([]SearchKnownRoutesByNodesRow, error)
SetNodeDefaultScope(ctx context.Context, arg SetNodeDefaultScopeParams) error
SetNodeMultibytePaths(ctx context.Context, id uuid.UUID) error
SetNodeMultibyteTraces(ctx context.Context, id uuid.UUID) error
+245 -88
View File
@@ -403,65 +403,6 @@ func (q *Queries) GetChannelByID(ctx context.Context, id int32) (Channel, error)
return i, err
}
const getCrossIATANeighbors = `-- name: GetCrossIATANeighbors :many
SELECT
n.id, n.name, n.node_type, n.latitude, n.longitude,
nn.iata AS neighbor_iata, nn.observation_count, nn.last_seen, nn.snr
FROM node_neighbors nn
JOIN nodes n ON n.id = nn.neighbor_id
WHERE nn.node_id = $1
AND nn.iata != $2
ORDER BY nn.last_seen DESC
`
type GetCrossIATANeighborsParams struct {
NodeID uuid.UUID `json:"node_id"`
Iata string `json:"iata"`
}
type GetCrossIATANeighborsRow struct {
ID uuid.UUID `json:"id"`
Name *string `json:"name"`
NodeType int16 `json:"node_type"`
Latitude *float64 `json:"latitude"`
Longitude *float64 `json:"longitude"`
NeighborIata string `json:"neighbor_iata"`
ObservationCount int64 `json:"observation_count"`
LastSeen pgtype.Timestamptz `json:"last_seen"`
Snr *float32 `json:"snr"`
}
// Returns neighbors of a node that are in a different IATA.
func (q *Queries) GetCrossIATANeighbors(ctx context.Context, arg GetCrossIATANeighborsParams) ([]GetCrossIATANeighborsRow, error) {
rows, err := q.db.Query(ctx, getCrossIATANeighbors, arg.NodeID, arg.Iata)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetCrossIATANeighborsRow{}
for rows.Next() {
var i GetCrossIATANeighborsRow
if err := rows.Scan(
&i.ID,
&i.Name,
&i.NodeType,
&i.Latitude,
&i.Longitude,
&i.NeighborIata,
&i.ObservationCount,
&i.LastSeen,
&i.Snr,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getHourlyStats = `-- name: GetHourlyStats :many
SELECT iata, hour, observation_count
@@ -540,20 +481,23 @@ func (q *Queries) GetIATABorder(ctx context.Context, iata string) (json.RawMessa
return border, err
}
const getKnownRoutesByNode = `-- name: GetKnownRoutesByNode :many
const getKnownRoutesByNodes = `-- name: GetKnownRoutesByNodes :many
SELECT id, node_ids, hash_prefix, iata, hop_count, first_seen, last_seen, observation_count
FROM known_routes
WHERE iata = $1
AND $2::uuid = ANY(node_ids)
FROM known_routes kr
WHERE kr.node_ids && $1::uuid[]
AND kr.iata = ANY($2::bpchar[])
AND ($1::uuid[])[array_position($2::bpchar[], kr.iata)] = ANY(kr.node_ids)
ORDER BY hop_count ASC, last_seen DESC
LIMIT $3
`
type GetKnownRoutesByNodeParams struct {
Iata string `json:"iata"`
Column2 uuid.UUID `json:"column_2"`
type GetKnownRoutesByNodesParams struct {
Nodes []uuid.UUID `json:"nodes"`
Iatas []string `json:"iatas"`
RowLimit int32 `json:"row_limit"`
}
type GetKnownRoutesByNodeRow struct {
type GetKnownRoutesByNodesRow struct {
ID int64 `json:"id"`
NodeIds []uuid.UUID `json:"node_ids"`
HashPrefix [][]byte `json:"hash_prefix"`
@@ -564,15 +508,17 @@ type GetKnownRoutesByNodeRow struct {
ObservationCount int64 `json:"observation_count"`
}
func (q *Queries) GetKnownRoutesByNode(ctx context.Context, arg GetKnownRoutesByNodeParams) ([]GetKnownRoutesByNodeRow, error) {
rows, err := q.db.Query(ctx, getKnownRoutesByNode, arg.Iata, arg.Column2)
// Routes containing @nodes[i] in IATA @iatas[i] (aligned, one node per IATA). The &&
// drives the node_ids GIN index; the indexed check keeps LIMIT counting real matches.
func (q *Queries) GetKnownRoutesByNodes(ctx context.Context, arg GetKnownRoutesByNodesParams) ([]GetKnownRoutesByNodesRow, error) {
rows, err := q.db.Query(ctx, getKnownRoutesByNodes, arg.Nodes, arg.Iatas, arg.RowLimit)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetKnownRoutesByNodeRow{}
items := []GetKnownRoutesByNodesRow{}
for rows.Next() {
var i GetKnownRoutesByNodeRow
var i GetKnownRoutesByNodesRow
if err := rows.Scan(
&i.ID,
&i.NodeIds,
@@ -593,6 +539,46 @@ func (q *Queries) GetKnownRoutesByNode(ctx context.Context, arg GetKnownRoutesBy
return items, nil
}
const getNeighborLinks = `-- name: GetNeighborLinks :many
SELECT node_id, neighbor_id, last_seen
FROM node_neighbors
WHERE (node_id = ANY($1::uuid[]) AND neighbor_id = ANY($2::uuid[]))
OR (node_id = ANY($2::uuid[]) AND neighbor_id = ANY($1::uuid[]))
`
type GetNeighborLinksParams struct {
ANodes []uuid.UUID `json:"a_nodes"`
BNodes []uuid.UUID `json:"b_nodes"`
}
type GetNeighborLinksRow struct {
NodeID uuid.UUID `json:"node_id"`
NeighborID uuid.UUID `json:"neighbor_id"`
LastSeen pgtype.Timestamptz `json:"last_seen"`
}
// Neighbor rows between @a_nodes and @b_nodes in either orientation: ingest writes
// adverts as (sender, forwarder) but traces as (receiver, sender). Callers normalise.
func (q *Queries) GetNeighborLinks(ctx context.Context, arg GetNeighborLinksParams) ([]GetNeighborLinksRow, error) {
rows, err := q.db.Query(ctx, getNeighborLinks, arg.ANodes, arg.BNodes)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetNeighborLinksRow{}
for rows.Next() {
var i GetNeighborLinksRow
if err := rows.Scan(&i.NodeID, &i.NeighborID, &i.LastSeen); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getNodeByID = `-- name: GetNodeByID :one
SELECT n.id, n.public_key, n.node_type, n.name, n.latitude, n.longitude, n.location_source, n.last_advert_at, n.supports_multibyte_paths, n.supports_multibyte_traces, n.default_scope_id, n.min_firmware_version, n.first_seen, n.last_seen, n.radio_freq_mhz, n.radio_sf, n.radio_bw_khz, n.metadata, n.device_clock_drift_seconds, ts.name AS default_scope_name,
EXISTS (SELECT 1 FROM observers o WHERE o.public_key = n.public_key) AS is_observer,
@@ -4856,6 +4842,170 @@ func (q *Queries) ResolvePathHashesP4(ctx context.Context, arg ResolvePathHashes
return items, nil
}
const resolveRelayHashPairsP1 = `-- name: ResolveRelayHashPairsP1 :many
SELECT ns.iata, ns.prefix_4 AS hash, ns.node_id
FROM node_short_ids ns
JOIN nodes n ON n.id = ns.node_id
WHERE ns.iata = ANY($1::bpchar[])
AND n.node_type IN (2, 3)
AND ns.prefix_1 = ANY($2::bytea[])
`
type ResolveRelayHashPairsP1Params struct {
Iatas []string `json:"iatas"`
Hashes [][]byte `json:"hashes"`
}
type ResolveRelayHashPairsP1Row struct {
Iata string `json:"iata"`
Hash []byte `json:"hash"`
NodeID uuid.UUID `json:"node_id"`
}
// Batch form of ResolvePathHashesP1 across IATAs; callers check uniqueness per IATA.
func (q *Queries) ResolveRelayHashPairsP1(ctx context.Context, arg ResolveRelayHashPairsP1Params) ([]ResolveRelayHashPairsP1Row, error) {
rows, err := q.db.Query(ctx, resolveRelayHashPairsP1, arg.Iatas, arg.Hashes)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ResolveRelayHashPairsP1Row{}
for rows.Next() {
var i ResolveRelayHashPairsP1Row
if err := rows.Scan(&i.Iata, &i.Hash, &i.NodeID); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const resolveRelayHashPairsP2 = `-- name: ResolveRelayHashPairsP2 :many
SELECT ns.iata, ns.prefix_4 AS hash, ns.node_id
FROM node_short_ids ns
JOIN nodes n ON n.id = ns.node_id
WHERE ns.iata = ANY($1::bpchar[])
AND n.node_type IN (2, 3)
AND ns.prefix_2 = ANY($2::bytea[])
`
type ResolveRelayHashPairsP2Params struct {
Iatas []string `json:"iatas"`
Hashes [][]byte `json:"hashes"`
}
type ResolveRelayHashPairsP2Row struct {
Iata string `json:"iata"`
Hash []byte `json:"hash"`
NodeID uuid.UUID `json:"node_id"`
}
// Batch form of ResolvePathHashesP2 across IATAs; callers check uniqueness per IATA.
func (q *Queries) ResolveRelayHashPairsP2(ctx context.Context, arg ResolveRelayHashPairsP2Params) ([]ResolveRelayHashPairsP2Row, error) {
rows, err := q.db.Query(ctx, resolveRelayHashPairsP2, arg.Iatas, arg.Hashes)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ResolveRelayHashPairsP2Row{}
for rows.Next() {
var i ResolveRelayHashPairsP2Row
if err := rows.Scan(&i.Iata, &i.Hash, &i.NodeID); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const resolveRelayHashPairsP3 = `-- name: ResolveRelayHashPairsP3 :many
SELECT ns.iata, ns.prefix_4 AS hash, ns.node_id
FROM node_short_ids ns
JOIN nodes n ON n.id = ns.node_id
WHERE ns.iata = ANY($1::bpchar[])
AND n.node_type IN (2, 3)
AND ns.prefix_3 = ANY($2::bytea[])
`
type ResolveRelayHashPairsP3Params struct {
Iatas []string `json:"iatas"`
Hashes [][]byte `json:"hashes"`
}
type ResolveRelayHashPairsP3Row struct {
Iata string `json:"iata"`
Hash []byte `json:"hash"`
NodeID uuid.UUID `json:"node_id"`
}
// Batch form of ResolvePathHashesP3 across IATAs; callers check uniqueness per IATA.
func (q *Queries) ResolveRelayHashPairsP3(ctx context.Context, arg ResolveRelayHashPairsP3Params) ([]ResolveRelayHashPairsP3Row, error) {
rows, err := q.db.Query(ctx, resolveRelayHashPairsP3, arg.Iatas, arg.Hashes)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ResolveRelayHashPairsP3Row{}
for rows.Next() {
var i ResolveRelayHashPairsP3Row
if err := rows.Scan(&i.Iata, &i.Hash, &i.NodeID); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const resolveRelayHashPairsP4 = `-- name: ResolveRelayHashPairsP4 :many
SELECT ns.iata, ns.prefix_4 AS hash, ns.node_id
FROM node_short_ids ns
JOIN nodes n ON n.id = ns.node_id
WHERE ns.iata = ANY($1::bpchar[])
AND n.node_type IN (2, 3)
AND ns.prefix_4 = ANY($2::bytea[])
`
type ResolveRelayHashPairsP4Params struct {
Iatas []string `json:"iatas"`
Hashes [][]byte `json:"hashes"`
}
type ResolveRelayHashPairsP4Row struct {
Iata string `json:"iata"`
Hash []byte `json:"hash"`
NodeID uuid.UUID `json:"node_id"`
}
// Batch form of ResolvePathHashesP4 across IATAs; callers check uniqueness per IATA.
func (q *Queries) ResolveRelayHashPairsP4(ctx context.Context, arg ResolveRelayHashPairsP4Params) ([]ResolveRelayHashPairsP4Row, error) {
rows, err := q.db.Query(ctx, resolveRelayHashPairsP4, arg.Iatas, arg.Hashes)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ResolveRelayHashPairsP4Row{}
for rows.Next() {
var i ResolveRelayHashPairsP4Row
if err := rows.Scan(&i.Iata, &i.Hash, &i.NodeID); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const saveChannelCatalogue = `-- name: SaveChannelCatalogue :exec
INSERT INTO meshmapper_channel_catalogues (iata, url, payload, etag, checked_at, attempted_at, next_attempt, last_error)
VALUES ($1, $2, $3::jsonb, $4::text,
@@ -5026,23 +5176,24 @@ func (q *Queries) SaveZoneList(ctx context.Context, arg SaveZoneListParams) erro
return err
}
const searchKnownRoutes = `-- name: SearchKnownRoutes :many
const searchKnownRoutesByNodes = `-- name: SearchKnownRoutesByNodes :many
SELECT id, node_ids, hash_prefix, iata, hop_count, first_seen, last_seen, observation_count
FROM known_routes
WHERE iata = $1
AND array_position(hash_prefix, $2::bytea) IS NOT NULL
AND array_position(hash_prefix, $3::bytea) IS NOT NULL
AND array_position(hash_prefix, $2::bytea) < array_position(hash_prefix, $3::bytea)
FROM known_routes kr
WHERE kr.node_ids && $1::uuid[]
AND kr.node_ids && $2::uuid[]
AND kr.iata = ANY($3::bpchar[])
ORDER BY hop_count ASC, last_seen DESC
LIMIT $4
`
type SearchKnownRoutesParams struct {
Iata string `json:"iata"`
Column2 []byte `json:"column_2"`
Column3 []byte `json:"column_3"`
type SearchKnownRoutesByNodesParams struct {
FromNodes []uuid.UUID `json:"from_nodes"`
ToNodes []uuid.UUID `json:"to_nodes"`
Iatas []string `json:"iatas"`
RowLimit int32 `json:"row_limit"`
}
type SearchKnownRoutesRow struct {
type SearchKnownRoutesByNodesRow struct {
ID int64 `json:"id"`
NodeIds []uuid.UUID `json:"node_ids"`
HashPrefix [][]byte `json:"hash_prefix"`
@@ -5053,17 +5204,23 @@ type SearchKnownRoutesRow struct {
ObservationCount int64 `json:"observation_count"`
}
// Returns known routes containing a subsequence from source to destination hash prefix.
// Verifies source appears before destination in the route.
func (q *Queries) SearchKnownRoutes(ctx context.Context, arg SearchKnownRoutesParams) ([]SearchKnownRoutesRow, error) {
rows, err := q.db.Query(ctx, searchKnownRoutes, arg.Iata, arg.Column2, arg.Column3)
// Routes holding a source and a destination candidate; callers check order and IATA.
// A route's hops resolve in its own IATA, so candidates from other IATAs can't match.
// Both && predicates use the node_ids GIN index.
func (q *Queries) SearchKnownRoutesByNodes(ctx context.Context, arg SearchKnownRoutesByNodesParams) ([]SearchKnownRoutesByNodesRow, error) {
rows, err := q.db.Query(ctx, searchKnownRoutesByNodes,
arg.FromNodes,
arg.ToNodes,
arg.Iatas,
arg.RowLimit,
)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SearchKnownRoutesRow{}
items := []SearchKnownRoutesByNodesRow{}
for rows.Next() {
var i SearchKnownRoutesRow
var i SearchKnownRoutesByNodesRow
if err := rows.Scan(
&i.ID,
&i.NodeIds,