Model: opus-5-5
This commit is contained in:
@@ -33,8 +33,10 @@ type liveCounts struct {
|
|||||||
|
|
||||||
// seed sets every count to the value read from the tables at startup. It runs
|
// seed sets every count to the value read from the tables at startup. It runs
|
||||||
// before any writer, so it needs no coordination with the adjust methods.
|
// before any writer, so it needs no coordination with the adjust methods.
|
||||||
func (c *liveCounts) seed(asns, prefixesV4, prefixesV6, peerings, peers, routesV4, routesV6 int,
|
func (c *liveCounts) seed(
|
||||||
distributionV4, distributionV6 []PrefixDistribution) {
|
asns, prefixesV4, prefixesV6, peerings, peers, routesV4, routesV6 int,
|
||||||
|
distributionV4, distributionV6 []PrefixDistribution,
|
||||||
|
) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
@@ -45,9 +47,11 @@ func (c *liveCounts) seed(asns, prefixesV4, prefixesV6, peerings, peers, routesV
|
|||||||
c.peers = peers
|
c.peers = peers
|
||||||
c.routesV4 = routesV4
|
c.routesV4 = routesV4
|
||||||
c.routesV6 = routesV6
|
c.routesV6 = routesV6
|
||||||
|
|
||||||
for _, entry := range distributionV4 {
|
for _, entry := range distributionV4 {
|
||||||
addAtMaskLength(c.distributionV4[:], entry.MaskLength, entry.Count)
|
addAtMaskLength(c.distributionV4[:], entry.MaskLength, entry.Count)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, entry := range distributionV6 {
|
for _, entry := range distributionV6 {
|
||||||
addAtMaskLength(c.distributionV6[:], entry.MaskLength, entry.Count)
|
addAtMaskLength(c.distributionV6[:], entry.MaskLength, entry.Count)
|
||||||
}
|
}
|
||||||
@@ -102,6 +106,7 @@ func (c *liveCounts) addToDistribution(maskLengthsV4, maskLengthsV6 []int, n int
|
|||||||
for _, maskLength := range maskLengthsV4 {
|
for _, maskLength := range maskLengthsV4 {
|
||||||
addAtMaskLength(c.distributionV4[:], maskLength, n)
|
addAtMaskLength(c.distributionV4[:], maskLength, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, maskLength := range maskLengthsV6 {
|
for _, maskLength := range maskLengthsV6 {
|
||||||
addAtMaskLength(c.distributionV6[:], maskLength, n)
|
addAtMaskLength(c.distributionV6[:], maskLength, n)
|
||||||
}
|
}
|
||||||
@@ -138,9 +143,11 @@ func (c *liveCounts) fill(s *Stats) {
|
|||||||
// ascending order, the way the distribution query returns them.
|
// ascending order, the way the distribution query returns them.
|
||||||
func distributionList(counts []int) []PrefixDistribution {
|
func distributionList(counts []int) []PrefixDistribution {
|
||||||
var list []PrefixDistribution
|
var list []PrefixDistribution
|
||||||
|
|
||||||
for maskLength, count := range counts {
|
for maskLength, count := range counts {
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
list = append(list, PrefixDistribution{MaskLength: maskLength, Count: count})
|
list = append(list,
|
||||||
|
PrefixDistribution{MaskLength: maskLength, Count: count})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +159,8 @@ func distributionList(counts []int) []PrefixDistribution {
|
|||||||
func (d *Database) countRows(ctx context.Context, table string) (int, error) {
|
func (d *Database) countRows(ctx context.Context, table string) (int, error) {
|
||||||
var n int
|
var n int
|
||||||
// table is one of a fixed set of literals below, never external input.
|
// table is one of a fixed set of literals below, never external input.
|
||||||
if err := d.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM "+table).Scan(&n); err != nil {
|
err := d.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM "+table).Scan(&n)
|
||||||
|
if err != nil {
|
||||||
return 0, fmt.Errorf("failed to count %s: %w", table, err)
|
return 0, fmt.Errorf("failed to count %s: %w", table, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,30 +175,37 @@ func (d *Database) seedCounts(ctx context.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
prefixesV4, err := d.countRows(ctx, "prefixes_v4")
|
prefixesV4, err := d.countRows(ctx, "prefixes_v4")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
prefixesV6, err := d.countRows(ctx, "prefixes_v6")
|
prefixesV6, err := d.countRows(ctx, "prefixes_v6")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
peerings, err := d.countRows(ctx, "peerings")
|
peerings, err := d.countRows(ctx, "peerings")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
peers, err := d.countRows(ctx, "bgp_peers")
|
peers, err := d.countRows(ctx, "bgp_peers")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
routesV4, err := d.countRows(ctx, "live_routes_v4")
|
|
||||||
|
routesV4, err := d.countRows(ctx, tableLiveRoutesV4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
routesV6, err := d.countRows(ctx, "live_routes_v6")
|
|
||||||
|
routesV6, err := d.countRows(ctx, tableLiveRoutesV6)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
distributionV4, distributionV6, err := d.GetPrefixDistributionContext(ctx)
|
distributionV4, distributionV6, err := d.GetPrefixDistributionContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
+1121
-825
File diff suppressed because it is too large
Load Diff
@@ -29,6 +29,8 @@ type Stats struct {
|
|||||||
// Store defines the interface for database operations. It provides methods for
|
// Store defines the interface for database operations. It provides methods for
|
||||||
// managing ASNs, prefixes, announcements, peerings, BGP peers, and live routes.
|
// managing ASNs, prefixes, announcements, peerings, BGP peers, and live routes.
|
||||||
// Implementations must be safe for concurrent use.
|
// Implementations must be safe for concurrent use.
|
||||||
|
//
|
||||||
|
//nolint:interfacebloat // the one seam handlers and tests depend on
|
||||||
type Store interface {
|
type Store interface {
|
||||||
// ASN operations
|
// ASN operations
|
||||||
GetOrCreateASN(number int, timestamp time.Time) (*ASN, error)
|
GetOrCreateASN(number int, timestamp time.Time) (*ASN, error)
|
||||||
@@ -57,8 +59,10 @@ type Store interface {
|
|||||||
UpsertLiveRouteBatch(routes []*LiveRoute) error
|
UpsertLiveRouteBatch(routes []*LiveRoute) error
|
||||||
DeleteLiveRoute(prefix string, originASN int, peerIP string) error
|
DeleteLiveRoute(prefix string, originASN int, peerIP string) error
|
||||||
DeleteLiveRouteBatch(deletions []LiveRouteDeletion) error
|
DeleteLiveRouteBatch(deletions []LiveRouteDeletion) error
|
||||||
GetPrefixDistribution() (ipv4 []PrefixDistribution, ipv6 []PrefixDistribution, err error)
|
GetPrefixDistribution() (
|
||||||
GetPrefixDistributionContext(ctx context.Context) (ipv4 []PrefixDistribution, ipv6 []PrefixDistribution, err error)
|
ipv4 []PrefixDistribution, ipv6 []PrefixDistribution, err error)
|
||||||
|
GetPrefixDistributionContext(ctx context.Context) (
|
||||||
|
ipv4 []PrefixDistribution, ipv6 []PrefixDistribution, err error)
|
||||||
GetLiveRouteCounts() (ipv4Count, ipv6Count int, err error)
|
GetLiveRouteCounts() (ipv4Count, ipv6Count int, err error)
|
||||||
GetLiveRouteCountsContext(ctx context.Context) (ipv4Count, ipv6Count int, err error)
|
GetLiveRouteCountsContext(ctx context.Context) (ipv4Count, ipv6Count int, err error)
|
||||||
|
|
||||||
@@ -79,7 +83,9 @@ type Store interface {
|
|||||||
GetPrefixDetails(prefix string) ([]LiveRoute, error)
|
GetPrefixDetails(prefix string) ([]LiveRoute, error)
|
||||||
GetPrefixDetailsContext(ctx context.Context, prefix string) ([]LiveRoute, error)
|
GetPrefixDetailsContext(ctx context.Context, prefix string) ([]LiveRoute, error)
|
||||||
GetRandomPrefixesByLength(maskLength, ipVersion, limit int) ([]LiveRoute, error)
|
GetRandomPrefixesByLength(maskLength, ipVersion, limit int) ([]LiveRoute, error)
|
||||||
GetRandomPrefixesByLengthContext(ctx context.Context, maskLength, ipVersion, limit int) ([]LiveRoute, error)
|
GetRandomPrefixesByLengthContext(
|
||||||
|
ctx context.Context, maskLength, ipVersion, limit int,
|
||||||
|
) ([]LiveRoute, error)
|
||||||
|
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
Close() error
|
Close() error
|
||||||
|
|||||||
@@ -19,29 +19,21 @@ func logSlowQuery(logger *logger.Logger, query string, start time.Time) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// queryRow wraps QueryRow with slow query logging
|
// queryRow wraps QueryRow with slow query logging
|
||||||
// nolint:unused // kept for consistency with other query wrappers
|
//
|
||||||
func (d *Database) queryRow(query string, args ...interface{}) *sql.Row {
|
//nolint:unused // kept for consistency with other query wrappers
|
||||||
|
func (d *Database) queryRow(query string, args ...any) *sql.Row {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
defer logSlowQuery(d.logger, query, start)
|
defer logSlowQuery(d.logger, query, start)
|
||||||
|
|
||||||
return d.db.QueryRow(query, args...)
|
return d.db.QueryRowContext(context.Background(), query, args...)
|
||||||
}
|
|
||||||
|
|
||||||
// query wraps Query with slow query logging
|
|
||||||
// nolint:unused // kept for future use to ensure all queries go through slow query logging
|
|
||||||
func (d *Database) query(query string, args ...interface{}) (*sql.Rows, error) {
|
|
||||||
start := time.Now()
|
|
||||||
defer logSlowQuery(d.logger, query, start)
|
|
||||||
|
|
||||||
return d.db.Query(query, args...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// exec wraps Exec with slow query logging
|
// exec wraps Exec with slow query logging
|
||||||
func (d *Database) exec(query string, args ...interface{}) error {
|
func (d *Database) exec(query string, args ...any) error {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
defer logSlowQuery(d.logger, query, start)
|
defer logSlowQuery(d.logger, query, start)
|
||||||
|
|
||||||
_, err := d.db.Exec(query, args...)
|
_, err := d.db.ExecContext(context.Background(), query, args...)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -49,35 +41,22 @@ func (d *Database) exec(query string, args ...interface{}) error {
|
|||||||
// loggingTx wraps sql.Tx to log slow queries
|
// loggingTx wraps sql.Tx to log slow queries
|
||||||
type loggingTx struct {
|
type loggingTx struct {
|
||||||
*sql.Tx
|
*sql.Tx
|
||||||
|
|
||||||
logger *logger.Logger
|
logger *logger.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryRow wraps sql.Tx.QueryRow to log slow queries
|
// QueryRow wraps sql.Tx.QueryRow to log slow queries
|
||||||
func (tx *loggingTx) QueryRow(query string, args ...interface{}) *sql.Row {
|
func (tx *loggingTx) QueryRow(query string, args ...any) *sql.Row {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
defer logSlowQuery(tx.logger, query, start)
|
defer logSlowQuery(tx.logger, query, start)
|
||||||
|
|
||||||
return tx.Tx.QueryRow(query, args...)
|
return tx.Tx.QueryRowContext(context.Background(), query, args...)
|
||||||
}
|
|
||||||
|
|
||||||
// Query wraps sql.Tx.Query to log slow queries
|
|
||||||
func (tx *loggingTx) Query(query string, args ...interface{}) (*sql.Rows, error) {
|
|
||||||
start := time.Now()
|
|
||||||
defer logSlowQuery(tx.logger, query, start)
|
|
||||||
|
|
||||||
return tx.Tx.Query(query, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryContext wraps sql.Tx.QueryContext to log slow queries
|
|
||||||
func (tx *loggingTx) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
|
|
||||||
start := time.Now()
|
|
||||||
defer logSlowQuery(tx.logger, query, start)
|
|
||||||
|
|
||||||
return tx.Tx.QueryContext(ctx, query, args...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryRowContext wraps sql.Tx.QueryRowContext to log slow queries
|
// QueryRowContext wraps sql.Tx.QueryRowContext to log slow queries
|
||||||
func (tx *loggingTx) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row {
|
func (tx *loggingTx) QueryRowContext(
|
||||||
|
ctx context.Context, query string, args ...any,
|
||||||
|
) *sql.Row {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
defer logSlowQuery(tx.logger, query, start)
|
defer logSlowQuery(tx.logger, query, start)
|
||||||
|
|
||||||
@@ -85,15 +64,17 @@ func (tx *loggingTx) QueryRowContext(ctx context.Context, query string, args ...
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Exec wraps sql.Tx.Exec to log slow queries
|
// Exec wraps sql.Tx.Exec to log slow queries
|
||||||
func (tx *loggingTx) Exec(query string, args ...interface{}) (sql.Result, error) {
|
func (tx *loggingTx) Exec(query string, args ...any) (sql.Result, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
defer logSlowQuery(tx.logger, query, start)
|
defer logSlowQuery(tx.logger, query, start)
|
||||||
|
|
||||||
return tx.Tx.Exec(query, args...)
|
return tx.Tx.ExecContext(context.Background(), query, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecContext wraps sql.Tx.ExecContext to log slow queries
|
// ExecContext wraps sql.Tx.ExecContext to log slow queries
|
||||||
func (tx *loggingTx) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
|
func (tx *loggingTx) ExecContext(
|
||||||
|
ctx context.Context, query string, args ...any,
|
||||||
|
) (sql.Result, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
defer logSlowQuery(tx.logger, query, start)
|
defer logSlowQuery(tx.logger, query, start)
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ func prefixMaskLength(prefix string) (int, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("invalid prefix %s: %w", prefix, err)
|
return 0, fmt.Errorf("invalid prefix %s: %w", prefix, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
maskLength, _ := network.Mask.Size()
|
maskLength, _ := network.Mask.Size()
|
||||||
|
|
||||||
return maskLength, nil
|
return maskLength, nil
|
||||||
|
|||||||
Reference in New Issue
Block a user