Skip to content

Commit

Permalink
feat: add versions of peer lists/sets/maps that report their sizes (#…
Browse files Browse the repository at this point in the history
…2300)

Adds collections that report their sizes to the libp2p metrics service.

Co-authored-by: Chad Nehemiah <chad.nehemiah94@gmail.com>

---------

Co-authored-by: Chad Nehemiah <chad.nehemiah94@gmail.com>
  • Loading branch information
achingbrain and maschad committed Dec 5, 2023
1 parent 3bf6387 commit 57944fa
Show file tree
Hide file tree
Showing 11 changed files with 607 additions and 7 deletions.
5 changes: 4 additions & 1 deletion packages/peer-collections/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@
},
"devDependencies": {
"@libp2p/peer-id-factory": "^4.0.0",
"aegir": "^41.0.2"
"@types/sinon": "^17.0.2",
"aegir": "^41.0.2",
"sinon": "^17.0.1",
"sinon-ts": "^2.0.0"
}
}
48 changes: 45 additions & 3 deletions packages/peer-collections/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
*
* PeerIds cache stringified versions of themselves so this should be a cheap operation.
*
* Tracked versions are also available which report their current size to the libp2p Metrics collector.
*
* @example Peer lists
*
* ```JavaScript
Expand All @@ -14,6 +16,18 @@
* list.push(peerId)
* ```
*
* @example Tracked peer lists
*
* * ```Typescript
* import { trackedPeerList } from '@libp2p/peer-collections'
* import { createLibp2p } from 'libp2p'
*
* const libp2p = await createLibp2p()
*
* const list = trackedPeerList({ name: 'my_metric_name', metrics: libp2p.metrics })
* list.push(peerId)
* ```
*
* @example Peer maps
*
* ```JavaScript
Expand All @@ -23,6 +37,18 @@
* map.set(peerId, 'value')
* ```
*
* @example Tracked peer maps
*
* * ```Typescript
* import { trackedPeerMap } from '@libp2p/peer-collections'
* import { createLibp2p } from 'libp2p'
*
* const libp2p = await createLibp2p()
*
* const list = trackedPeerMap({ name: 'my_metric_name', metrics: libp2p.metrics })
* map.set(peerId, 'value')
* ```
*
* @example Peer sets
*
* ```JavaScript
Expand All @@ -31,8 +57,24 @@
* const set = peerSet()
* set.add(peerId)
* ```
*
* @example Tracked peer sets
*
* * ```Typescript
* import { trackedPeerSet } from '@libp2p/peer-collections'
* import { createLibp2p } from 'libp2p'
*
* const libp2p = await createLibp2p()
*
* const list = trackedPeerSet({ name: 'my_metric_name', metrics: libp2p.metrics })
* map.add(peerId)
* ```
*/

export { PeerMap } from './map.js'
export { PeerSet } from './set.js'
export { PeerList } from './list.js'
export { PeerMap, peerMap } from './map.js'
export { PeerSet, peerSet } from './set.js'
export { PeerList, peerList } from './list.js'

export { trackedPeerMap } from './tracked-map.js'
export { trackedPeerSet } from './tracked-set.js'
export { trackedPeerList } from './tracked-list.js'
10 changes: 9 additions & 1 deletion packages/peer-collections/src/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import type { PeerId } from '@libp2p/interface'
* ```
*/
export class PeerList {
private readonly list: string[]
private list: string[]

constructor (list?: PeerList | Iterable<PeerId>) {
this.list = []
Expand Down Expand Up @@ -148,7 +148,15 @@ export class PeerList {
return len
}

clear (): void {
this.list = []
}

get length (): number {
return this.list.length
}
}

export function peerList (): PeerList {
return new PeerList()
}
8 changes: 6 additions & 2 deletions packages/peer-collections/src/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ export class PeerMap <T> {
this.map.clear()
}

delete (peer: PeerId): void {
this.map.delete(peer.toString())
delete (peer: PeerId): boolean {
return this.map.delete(peer.toString())
}

entries (): IterableIterator<[PeerId, T]> {
Expand Down Expand Up @@ -88,3 +88,7 @@ export class PeerMap <T> {
return this.map.size
}
}

export function peerMap <T> (): PeerMap<T> {
return new PeerMap<T>()
}
4 changes: 4 additions & 0 deletions packages/peer-collections/src/set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,7 @@ export class PeerSet {
return output
}
}

export function peerSet (): PeerSet {
return new PeerSet()
}
92 changes: 92 additions & 0 deletions packages/peer-collections/src/tracked-list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { PeerList } from './list.js'
import type { Metric, Metrics, PeerId } from '@libp2p/interface'

export interface TrackedPeerListInit {
name: string
metrics: Metrics
}

class TrackedPeerList extends PeerList {
private readonly metric: Metric

constructor (init: TrackedPeerListInit) {
super()

const { name, metrics } = init

this.metric = metrics.registerMetric(name)
this.updateComponentMetric()
}

pop (): PeerId | undefined {
const peerId = super.pop()
this.updateComponentMetric()
return peerId
}

push (...peerIds: PeerId[]): void {
super.push(...peerIds)
this.updateComponentMetric()
}

shift (): PeerId | undefined {
const peerId = super.shift()
this.updateComponentMetric()
return peerId
}

unshift (...peerIds: PeerId[]): number {
const result = super.unshift(...peerIds)
this.updateComponentMetric()
return result
}

clear (): void {
super.clear()
this.updateComponentMetric()
}

private updateComponentMetric (): void {
this.metric.update(this.length)
}
}

export interface CreateTrackedPeerListInit {
/**
* The metric name to use
*/
name: string

/**
* A metrics implementation
*/
metrics?: Metrics
}

/**
* Creates a PeerList that reports it's size to the libp2p Metrics service
*
* @example
*
* * ```Typescript
* import { trackedPeerList } from '@libp2p/peer-collections'
* import { createLibp2p } from 'libp2p'
*
* const libp2p = await createLibp2p()
*
* const list = trackedPeerList({ name: 'my_metric_name', metrics: libp2p.metrics })
* list.push(peerId)
* ```
*/
export function trackedPeerList (config: CreateTrackedPeerListInit): PeerList {
const { name, metrics } = config
let map: PeerList

if (metrics != null) {
map = new TrackedPeerList({ name, metrics })
} else {
map = new PeerList()
}

return map
}
81 changes: 81 additions & 0 deletions packages/peer-collections/src/tracked-map.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { PeerMap } from './map.js'
import type { Metric, Metrics, PeerId } from '@libp2p/interface'

export interface TrackedPeerMapInit {
name: string
metrics: Metrics
}

class TrackedPeerMap<V> extends PeerMap<V> {
private readonly metric: Metric

constructor (init: TrackedPeerMapInit) {
super()

const { name, metrics } = init

this.metric = metrics.registerMetric(name)
this.updateComponentMetric()
}

set (key: PeerId, value: V): this {
super.set(key, value)
this.updateComponentMetric()
return this
}

delete (key: PeerId): boolean {
const deleted = super.delete(key)
this.updateComponentMetric()
return deleted
}

clear (): void {
super.clear()
this.updateComponentMetric()
}

private updateComponentMetric (): void {
this.metric.update(this.size)
}
}

export interface CreateTrackedPeerMapInit {
/**
* The metric name to use
*/
name: string

/**
* A metrics implementation
*/
metrics?: Metrics
}

/**
* Creates a PeerMap that reports it's size to the libp2p Metrics service
*
* @example
*
* * ```Typescript
* import { trackedPeerMap } from '@libp2p/peer-collections'
* import { createLibp2p } from 'libp2p'
*
* const libp2p = await createLibp2p()
*
* const list = trackedPeerMap({ name: 'my_metric_name', metrics: libp2p.metrics })
* map.set(peerId, 'value')
* ```
*/
export function trackedPeerMap <V> (config: CreateTrackedPeerMapInit): PeerMap<V> {
const { name, metrics } = config
let map: PeerMap<V>

if (metrics != null) {
map = new TrackedPeerMap<V>({ name, metrics })
} else {
map = new PeerMap<V>()
}

return map
}
79 changes: 79 additions & 0 deletions packages/peer-collections/src/tracked-set.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { PeerSet } from './set.js'
import type { Metric, Metrics, PeerId } from '@libp2p/interface'

export interface TrackedPeerSetInit {
name: string
metrics: Metrics
}

class TrackedPeerSet extends PeerSet {
private readonly metric: Metric

constructor (init: TrackedPeerSetInit) {
super()

const { name, metrics } = init

this.metric = metrics.registerMetric(name)
this.updateComponentMetric()
}

add (peer: PeerId): void {
super.add(peer)
this.updateComponentMetric()
}

delete (peer: PeerId): void {
super.delete(peer)
this.updateComponentMetric()
}

clear (): void {
super.clear()
this.updateComponentMetric()
}

private updateComponentMetric (): void {
this.metric.update(this.size)
}
}

export interface CreateTrackedPeerSetInit {
/**
* The metric name to use
*/
name: string

/**
* A metrics implementation
*/
metrics?: Metrics
}

/**
* Creates a PeerSet that reports it's size to the libp2p Metrics service
*
* @example Tracked peer sets
*
* * ```Typescript
* import { trackedPeerSet } from '@libp2p/peer-collections'
* import { createLibp2p } from 'libp2p'
*
* const libp2p = await createLibp2p()
*
* const list = trackedPeerSet({ name: 'my_metric_name', metrics: libp2p.metrics })
* map.add(peerId)
* ```
*/
export function trackedPeerSet (config: CreateTrackedPeerSetInit): PeerSet {
const { name, metrics } = config
let map: PeerSet

if (metrics != null) {
map = new TrackedPeerSet({ name, metrics })
} else {
map = new PeerSet()
}

return map
}
Loading

0 comments on commit 57944fa

Please sign in to comment.