Stop decoding unused Community and Raw fields of RIS messages (closes #9)
check / check (push) Failing after 1s
check / check (push) Failing after 1s
Community and Raw are decoded from every live message and read by no handler; Raw is the hex of the whole BGP message. Each parsed message sits in up to four handler queues, so retaining them is a large share of queue memory. Tagging both json:"-" keeps them out of the decoded message while the fields handlers use still decode. A decode test over docs/message-examples.json confirms both stay empty and the used fields (Path, Announcements) still populate. Model: opus-4-8
This commit was merged in pull request #18.
This commit is contained in:
+22
-18
@@ -63,24 +63,28 @@ type RISLiveMessage struct {
|
|||||||
// the actual BGP update data including AS path, communities, announcements,
|
// the actual BGP update data including AS path, communities, announcements,
|
||||||
// and withdrawals.
|
// and withdrawals.
|
||||||
type RISMessage struct {
|
type RISMessage struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Timestamp float64 `json:"timestamp"`
|
Timestamp float64 `json:"timestamp"`
|
||||||
ParsedTimestamp time.Time `json:"-"` // Parsed from Timestamp field
|
ParsedTimestamp time.Time `json:"-"` // Parsed from Timestamp field
|
||||||
Peer string `json:"peer"`
|
Peer string `json:"peer"`
|
||||||
PeerASN string `json:"peer_asn"`
|
PeerASN string `json:"peer_asn"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Host string `json:"host"`
|
Host string `json:"host"`
|
||||||
RRC string `json:"rrc,omitempty"`
|
RRC string `json:"rrc,omitempty"`
|
||||||
MrtTime float64 `json:"mrt_time,omitempty"`
|
MrtTime float64 `json:"mrt_time,omitempty"`
|
||||||
SocketTime float64 `json:"socket_time,omitempty"`
|
SocketTime float64 `json:"socket_time,omitempty"`
|
||||||
Path ASPath `json:"path,omitempty"`
|
Path ASPath `json:"path,omitempty"`
|
||||||
Community [][]int `json:"community,omitempty"`
|
// Community and Raw are present in the feed but read by no handler.
|
||||||
Origin string `json:"origin,omitempty"`
|
// They are the largest fields on a message that lives in up to four
|
||||||
MED *int `json:"med,omitempty"`
|
// handler queues, so json:"-" keeps them out of the decoded message
|
||||||
LocalPref *int `json:"local_pref,omitempty"`
|
// to save queue memory. Do not decode them without a consumer.
|
||||||
Announcements []RISAnnouncement `json:"announcements,omitempty"`
|
Community [][]int `json:"-"`
|
||||||
Withdrawals []string `json:"withdrawals,omitempty"`
|
Origin string `json:"origin,omitempty"`
|
||||||
Raw string `json:"raw,omitempty"`
|
MED *int `json:"med,omitempty"`
|
||||||
|
LocalPref *int `json:"local_pref,omitempty"`
|
||||||
|
Announcements []RISAnnouncement `json:"announcements,omitempty"`
|
||||||
|
Withdrawals []string `json:"withdrawals,omitempty"`
|
||||||
|
Raw string `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RISAnnouncement represents a BGP route announcement within a RIS message.
|
// RISAnnouncement represents a BGP route announcement within a RIS message.
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package ristypes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// messageExamplesPath is the captured RIS Live feed used as decode fixtures,
|
||||||
|
// one JSON message per line.
|
||||||
|
const messageExamplesPath = "../../docs/message-examples.json"
|
||||||
|
|
||||||
|
// TestDecodeDropsCommunityAndRaw decodes every captured message the way the
|
||||||
|
// streamer does and checks that the fields no handler reads (Community, Raw)
|
||||||
|
// stay empty while the fields handlers use (Path, Announcements) still decode.
|
||||||
|
func TestDecodeDropsCommunityAndRaw(t *testing.T) {
|
||||||
|
f, err := os.Open(messageExamplesPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("open fixtures: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
var messages, withPath, withAnnouncements int
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(f)
|
||||||
|
scanner.Buffer(make([]byte, 0, 64*1024), 1024*1024)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Bytes()
|
||||||
|
if len(line) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var wrapper RISLiveMessage
|
||||||
|
if err := json.Unmarshal(line, &wrapper); err != nil {
|
||||||
|
t.Fatalf("unmarshal message %d: %v", messages+1, err)
|
||||||
|
}
|
||||||
|
messages++
|
||||||
|
|
||||||
|
msg := wrapper.Data
|
||||||
|
if msg.Community != nil {
|
||||||
|
t.Errorf("message %d: Community decoded, want empty: %v", messages, msg.Community)
|
||||||
|
}
|
||||||
|
if msg.Raw != "" {
|
||||||
|
t.Errorf("message %d: Raw decoded, want empty", messages)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(msg.Path) > 0 {
|
||||||
|
withPath++
|
||||||
|
}
|
||||||
|
if len(msg.Announcements) > 0 {
|
||||||
|
withAnnouncements++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
t.Fatalf("scan fixtures: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if messages == 0 {
|
||||||
|
t.Fatal("no messages decoded from fixtures")
|
||||||
|
}
|
||||||
|
// The fixtures include announcement messages; a used field must still decode,
|
||||||
|
// otherwise an empty Community/Raw would prove nothing.
|
||||||
|
if withPath == 0 || withAnnouncements == 0 {
|
||||||
|
t.Fatalf("used fields did not decode: withPath=%d withAnnouncements=%d", withPath, withAnnouncements)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user