Skip to content

Commit 3528df8

Browse files
authored
fix: add tracking for long-lived maps (#3158)
Adds metrics tracking the size of long-lived maps to make debugging memory leaks easier.
1 parent 01328a0 commit 3528df8

File tree

10 files changed

+61
-13
lines changed

10 files changed

+61
-13
lines changed

packages/libp2p/src/address-manager/dns-mappings.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { isPrivateIp } from '@libp2p/utils/private-ip'
2+
import { trackedMap } from '@libp2p/utils/tracked-map'
23
import { multiaddr, protocols } from '@multiformats/multiaddr'
34
import type { AddressManagerComponents, AddressManagerInit } from './index.js'
45
import type { Logger } from '@libp2p/interface'
@@ -31,7 +32,10 @@ export class DNSMappings {
3132

3233
constructor (components: AddressManagerComponents, init: AddressManagerInit = {}) {
3334
this.log = components.logger.forComponent('libp2p:address-manager:dns-mappings')
34-
this.mappings = new Map()
35+
this.mappings = trackedMap({
36+
name: 'libp2p_address_manager_dns_mappings',
37+
metrics: components.metrics
38+
})
3539
}
3640

3741
has (ma: Multiaddr): boolean {

packages/libp2p/src/address-manager/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { DNSMappings } from './dns-mappings.js'
1010
import { IPMappings } from './ip-mappings.js'
1111
import { ObservedAddresses } from './observed-addresses.js'
1212
import { TransportAddresses } from './transport-addresses.js'
13-
import type { ComponentLogger, Libp2pEvents, Logger, TypedEventTarget, PeerId, PeerStore } from '@libp2p/interface'
13+
import type { ComponentLogger, Libp2pEvents, Logger, TypedEventTarget, PeerId, PeerStore, Metrics } from '@libp2p/interface'
1414
import type { AddressManager as AddressManagerInterface, TransportManager, NodeAddress, ConfirmAddressOptions } from '@libp2p/interface-internal'
1515
import type { Filter } from '@libp2p/utils/filters'
1616
import type { Multiaddr } from '@multiformats/multiaddr'
@@ -83,6 +83,7 @@ export interface AddressManagerComponents {
8383
peerStore: PeerStore
8484
events: TypedEventTarget<Libp2pEvents>
8585
logger: ComponentLogger
86+
metrics?: Metrics
8687
}
8788

8889
/**

packages/libp2p/src/address-manager/ip-mappings.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { isIPv4 } from '@chainsafe/is-ip'
2+
import { trackedMap } from '@libp2p/utils/tracked-map'
23
import { multiaddr, protocols } from '@multiformats/multiaddr'
34
import type { AddressManagerComponents, AddressManagerInit } from './index.js'
45
import type { Logger } from '@libp2p/interface'
@@ -32,7 +33,10 @@ export class IPMappings {
3233

3334
constructor (components: AddressManagerComponents, init: AddressManagerInit = {}) {
3435
this.log = components.logger.forComponent('libp2p:address-manager:ip-mappings')
35-
this.mappings = new Map()
36+
this.mappings = trackedMap({
37+
name: 'libp2p_address_manager_ip_mappings',
38+
metrics: components.metrics
39+
})
3640
}
3741

3842
has (ma: Multiaddr): boolean {

packages/libp2p/src/address-manager/observed-addresses.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { isLinkLocal } from '@libp2p/utils/multiaddr/is-link-local'
22
import { isPrivate } from '@libp2p/utils/multiaddr/is-private'
3+
import { trackedMap } from '@libp2p/utils/tracked-map'
34
import { multiaddr } from '@multiformats/multiaddr'
45
import type { AddressManagerComponents, AddressManagerInit } from './index.js'
56
import type { Logger } from '@libp2p/interface'
@@ -23,7 +24,10 @@ export class ObservedAddresses {
2324

2425
constructor (components: AddressManagerComponents, init: AddressManagerInit = {}) {
2526
this.log = components.logger.forComponent('libp2p:address-manager:observed-addresses')
26-
this.addresses = new Map()
27+
this.addresses = trackedMap({
28+
name: 'libp2p_address_manager_observed_addresses',
29+
metrics: components.metrics
30+
})
2731
this.maxObservedAddresses = init.maxObservedAddresses ?? defaultValues.maxObservedAddresses
2832
}
2933

packages/libp2p/src/address-manager/transport-addresses.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { isNetworkAddress } from '@libp2p/utils/multiaddr/is-network-address'
22
import { isPrivate } from '@libp2p/utils/multiaddr/is-private'
3+
import { trackedMap } from '@libp2p/utils/tracked-map'
34
import type { AddressManagerComponents, AddressManagerInit } from './index.js'
45
import type { Logger } from '@libp2p/interface'
56
import type { NodeAddress } from '@libp2p/interface-internal'
@@ -22,7 +23,10 @@ export class TransportAddresses {
2223

2324
constructor (components: AddressManagerComponents, init: AddressManagerInit = {}) {
2425
this.log = components.logger.forComponent('libp2p:address-manager:observed-addresses')
25-
this.addresses = new Map()
26+
this.addresses = trackedMap({
27+
name: 'libp2p_address_manager_transport_addresses',
28+
metrics: components.metrics
29+
})
2630
this.maxObservedAddresses = init.maxObservedAddresses ?? defaultValues.maxObservedAddresses
2731
}
2832

packages/libp2p/src/registrar.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { InvalidParametersError } from '@libp2p/interface'
22
import { mergeOptions } from '@libp2p/utils/merge-options'
3+
import { trackedMap } from '@libp2p/utils/tracked-map'
34
import * as errorsJs from './errors.js'
4-
import type { IdentifyResult, Libp2pEvents, Logger, PeerUpdate, TypedEventTarget, PeerId, PeerStore, Topology, StreamHandler, StreamHandlerRecord, StreamHandlerOptions, AbortOptions } from '@libp2p/interface'
5+
import type { IdentifyResult, Libp2pEvents, Logger, PeerUpdate, TypedEventTarget, PeerId, PeerStore, Topology, StreamHandler, StreamHandlerRecord, StreamHandlerOptions, AbortOptions, Metrics } from '@libp2p/interface'
56
import type { Registrar as RegistrarInterface } from '@libp2p/interface-internal'
67
import type { ComponentLogger } from '@libp2p/logger'
78

@@ -13,6 +14,7 @@ export interface RegistrarComponents {
1314
peerStore: PeerStore
1415
events: TypedEventTarget<Libp2pEvents>
1516
logger: ComponentLogger
17+
metrics?: Metrics
1618
}
1719

1820
/**
@@ -25,10 +27,24 @@ export class Registrar implements RegistrarInterface {
2527
private readonly components: RegistrarComponents
2628

2729
constructor (components: RegistrarComponents) {
30+
this.components = components
2831
this.log = components.logger.forComponent('libp2p:registrar')
2932
this.topologies = new Map()
30-
this.handlers = new Map()
31-
this.components = components
33+
components.metrics?.registerMetricGroup('libp2p_registrar_topologies', {
34+
calculate: () => {
35+
const output: Record<string, number> = {}
36+
37+
for (const [key, value] of this.topologies) {
38+
output[key] = value.size
39+
}
40+
41+
return output
42+
}
43+
})
44+
this.handlers = trackedMap({
45+
name: 'libp2p_registrar_protocol_handlers',
46+
metrics: components.metrics
47+
})
3248

3349
this._onDisconnect = this._onDisconnect.bind(this)
3450
this._onPeerUpdate = this._onPeerUpdate.bind(this)

packages/libp2p/src/transport-manager.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ export class DefaultTransportManager implements TransportManager, Startable {
4242
this.log = components.logger.forComponent('libp2p:transports')
4343
this.components = components
4444
this.started = false
45-
this.transports = new Map<string, Transport>()
45+
this.transports = trackedMap({
46+
name: 'libp2p_transport_manager_transports',
47+
metrics: this.components.metrics
48+
})
4649
this.listeners = trackedMap({
4750
name: 'libp2p_transport_manager_listeners',
4851
metrics: this.components.metrics

packages/libp2p/src/upgrader.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { InvalidMultiaddrError, TooManyInboundProtocolStreamsError, TooManyOutboundProtocolStreamsError, LimitedConnectionError, setMaxListeners, InvalidPeerIdError } from '@libp2p/interface'
22
import * as mss from '@libp2p/multistream-select'
33
import { peerIdFromString } from '@libp2p/peer-id'
4+
import { trackedMap } from '@libp2p/utils/tracked-map'
45
import { anySignal } from 'any-signal'
56
import { CustomProgressEvent } from 'progress-events'
67
import { raceSignal } from 'race-signal'
@@ -130,13 +131,19 @@ export class Upgrader implements UpgraderInterface {
130131

131132
constructor (components: UpgraderComponents, init: UpgraderInit) {
132133
this.components = components
133-
this.connectionEncrypters = new Map()
134+
this.connectionEncrypters = trackedMap({
135+
name: 'libp2p_upgrader_connection_encrypters',
136+
metrics: this.components.metrics
137+
})
134138

135139
init.connectionEncrypters.forEach(encrypter => {
136140
this.connectionEncrypters.set(encrypter.protocol, encrypter)
137141
})
138142

139-
this.streamMuxers = new Map()
143+
this.streamMuxers = trackedMap({
144+
name: 'libp2p_upgrader_stream_multiplexers',
145+
metrics: this.components.metrics
146+
})
140147

141148
init.streamMuxers.forEach(muxer => {
142149
this.streamMuxers.set(muxer.protocol, muxer)

packages/protocol-autonat/src/autonat.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { isGlobalUnicast } from '@libp2p/utils/multiaddr/is-global-unicast'
66
import { isPrivate } from '@libp2p/utils/multiaddr/is-private'
77
import { PeerQueue } from '@libp2p/utils/peer-queue'
88
import { repeatingTask } from '@libp2p/utils/repeating-task'
9+
import { trackedMap } from '@libp2p/utils/tracked-map'
910
import { multiaddr, protocols } from '@multiformats/multiaddr'
1011
import { anySignal } from 'any-signal'
1112
import { pbStream } from 'it-protobuf-stream'
@@ -105,7 +106,10 @@ export class AutoNATService implements Startable {
105106
this.maxOutboundStreams = init.maxOutboundStreams ?? MAX_OUTBOUND_STREAMS
106107
this.connectionThreshold = init.connectionThreshold ?? DEFAULT_CONNECTION_THRESHOLD
107108
this.maxMessageSize = init.maxMessageSize ?? MAX_MESSAGE_SIZE
108-
this.dialResults = new Map()
109+
this.dialResults = trackedMap({
110+
name: 'libp2p_autonat_dial_results',
111+
metrics: components.metrics
112+
})
109113
this.findPeers = repeatingTask(this.findRandomPeers.bind(this), 60_000)
110114
this.addressFilter = createScalableCuckooFilter(1024)
111115
}

packages/protocol-autonat/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
*/
3232

3333
import { AutoNATService } from './autonat.js'
34-
import type { ComponentLogger, Libp2pEvents, PeerId, PeerStore, TypedEventTarget } from '@libp2p/interface'
34+
import type { ComponentLogger, Libp2pEvents, Metrics, PeerId, PeerStore, TypedEventTarget } from '@libp2p/interface'
3535
import type { AddressManager, ConnectionManager, RandomWalk, Registrar, TransportManager } from '@libp2p/interface-internal'
3636

3737
export interface AutoNATServiceInit {
@@ -95,6 +95,7 @@ export interface AutoNATComponents {
9595
randomWalk: RandomWalk
9696
events: TypedEventTarget<Libp2pEvents>
9797
peerStore: PeerStore
98+
metrics?: Metrics
9899
}
99100

100101
export function autoNAT (init: AutoNATServiceInit = {}): (components: AutoNATComponents) => unknown {

0 commit comments

Comments
 (0)